package by.yativem.commons.utils.matrix;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import by.ins.life.INuclear;


public class Matrix<T extends INuclear< ? extends Object>> implements IMatrix<T> {

	private static final long serialVersionUID = 1L;
	Object[][] matrix;

	protected void init(T initialValue) {
		for (int i = 0; i < getRowsCount(); i++) {
			for (int j = 0; j < getColumnsCount(); j++) {
				matrix[i][j] = initialValue.clone();
			}
		}
	}

	

	protected Matrix(Object[][] matrix) {
		this.matrix = matrix;
	}

	public Matrix() {

	}

	public Matrix(int rows, int columns) {		
		matrix = new Object[rows][columns];
		
		for (int i = 0; i < getRowsCount(); i++) {
			for (int j = 0; j < getColumnsCount(); j++) {
				matrix[i][j] = null;
			}
		}
	}

	public Matrix(int rows, int columns, T initialValue) {
		matrix = new Object[rows][columns];
		if (initialValue != null) {
			init(initialValue);
		}else{
			throw new NullPointerException();
		}
	}

	@Override
	public int getRowsCount() {
		return matrix.length;
	}

	@SuppressWarnings("unchecked")
	@Override
	public T get(int r, int c) {
		return (T) matrix[r][c];
	}

/*	
	public UnmodifiableList<INuclear> getRow(int r) {
		return new UnmodifiableRow(r);
	}

	public UnmodifiableList<INuclear> getColumn(int column) {
		return new UnmodifiableColumn(column);
	}
*/
	@Override
	public int getColumnsCount() {
		return matrix[0].length;
	}

	@Override
	public void set(int r, int c, T t) {
		matrix[r][c] = t;
	}

	@Override
	public Object clone() {
		Object[][] cloneMatrix = matrix.clone();
		return new Matrix<T>(cloneMatrix);
	}
	
	

	class UnmodifiableColumn implements UnmodifiableList<INuclear> {
		private int columnIndx = -1;

		public UnmodifiableColumn(int columnIndx) {
			this.columnIndx = columnIndx;
		}

		@Override
		public INuclear<?> get(int x) {
			return (INuclear<?>) matrix[x][columnIndx];
		}

		@Override
		public Iterator<INuclear> getIterator() {

			return new Iterator<INuclear>() {
				private int position = -1;

				@Override
				public void remove() {
					throw new UnsupportedOperationException();
				}

				@Override
				public INuclear next() {
					position++;
					return (INuclear) matrix[position][columnIndx];
				}

				@Override
				public boolean hasNext() {
					return matrix[0].length > position;
				}
			};
		}

		@Override
		public Iterator<INuclear> iterator() {
			return getIterator();
		}

	}

	class UnmodifiableRow implements UnmodifiableList<INuclear> {
		int matrixRowInd = -1;

		protected UnmodifiableRow(int rowIndx) {
			this.matrixRowInd = rowIndx;
		}

		@Override
		public INuclear get(int x) {
			return (INuclear) matrix[matrixRowInd][x];
		}

		@Override
		public Iterator<INuclear> getIterator() {
			return new Iterator<INuclear>() {

				private int position = -1;

				@Override
				public boolean hasNext() {
					return position < matrix.length;
				}

				@Override
				public INuclear next() {
					position++;
					return (INuclear) matrix[matrixRowInd][position];
				}

				@Override
				public void remove() {
					throw new UnsupportedOperationException();

				}
			};
		}

		@Override
		public Iterator<INuclear> iterator() {
			return getIterator();
		}

	}

	@SuppressWarnings("unchecked")
	@Override
	public void process(IMatrixHandler<T> handler) {
		for (int i = 0; i < getRowsCount(); i++) {
			for (int j = 0; j < getColumnsCount(); j++) {
				handler.callBack(i, j, (T) matrix[i][j]);
			}
		}

	}
	
	public void processColumn(int column, IMatrixHandler<T> handler){
		for (int j = 0; j < getRowsCount(); j++) {
			handler.callBack(j, column, (T) matrix[j][column]);
		}
		
	}

	public void processRow(int row, IMatrixHandler<T> handler){
		for (int j = 0; j < getColumnsCount(); j++) {
			handler.callBack(row, j, (T) matrix[row][j]);
		}
		
	}


	@Override
	public IMatrix<T>  getImmutable() {
		// TODO Auto-generated method stub
		return null;
	}



	@Override
	public List<T> getRow(int r) {
		List<T> t =(List<T>) Arrays.asList( matrix[r]);
		return t;
	//	return null;
	}



	@Override
	public List<T> getColumn(int column) {
		 
		List<T> result = new ArrayList<T>(getRowsCount());
		for(int i  = 0;  i < getRowsCount(); i ++){
			result.add( (T) matrix[i][column]);
		}
		
		return result; 
	//	return null;
	}
	
	public String toString(){
		StringBuilder sb = new StringBuilder();
		for(int i =0; i < this.getColumnsCount(); i++){
			for(int j =0; j< this.getRowsCount(); j++ ){
				sb.append("[").append(this.get(i, j).toString() ).append(" ]");
			}
			sb.append("\n");
		}		
		return sb.toString();
	}

}
